package service

import (
	"context"
	"net/http"

	"github.com/go-kratos/kratos/v2/errors"
	"github.com/go-kratos/kratos/v2/log"

	pb "gitee.com/danqingzhao/go-dango/api/user/button/v1"
	"gitee.com/danqingzhao/go-dango/apps/user/biz"
	"gitee.com/danqingzhao/go-dango/pkg/common/core"
	"gitee.com/danqingzhao/go-dango/pkg/proto/settings"
)

func ButtonSchemasOutBase(
	ctx context.Context,
	logHelper *log.Helper,
	m biz.ButtonModel,
) *pb.ButtonOutBase {
	return &pb.ButtonOutBase{
		Id:           m.Id,
		CreatedTime:  m.CreatedAt.String(),
		UpdatedTime:  m.UpdatedAt.String(),
		Name:         m.Name,
		ArrangeOrder: m.ArrangeOrder,
		IsActive:     m.IsActive,
		Descr:        m.Descr,
		MenuId:       m.MenuId,
	}
}

func ButtonSchemasOut(
	ctx context.Context,
	logHelper *log.Helper,
	m biz.ButtonModel,
) (*pb.ButtonOut, *errors.Error) {
	mo, err := MenuSchemasOutBase(ctx, logHelper, m.Menu)
	if err != nil {
		return nil, err
	}
	pmso := ListPermissionModelToSchemasOutBase(ctx, logHelper, m.Permissions)
	return &pb.ButtonOut{
		Id:           m.Id,
		CreatedTime:  m.CreatedAt.String(),
		UpdatedTime:  m.UpdatedAt.String(),
		Name:         m.Name,
		ArrangeOrder: m.ArrangeOrder,
		IsActive:     m.IsActive,
		Descr:        m.Descr,
		Menu:         mo,
		Permissions:  pmso,
	}, nil
}

func ListButtonModelToSchemasOutBase(
	ctx context.Context,
	logHelper *log.Helper,
	ms []biz.ButtonModel,
) ([]*pb.ButtonOutBase, *errors.Error) {
	mso := make([]*pb.ButtonOutBase, 0, len(ms))
	if len(ms) > 0 {
		for _, m := range ms {
			mo := ButtonSchemasOutBase(ctx, logHelper, m)
			mso = append(mso, mo)
		}
	}
	return mso, nil
}

type ButtonService struct {
	pb.UnimplementedButtonServer
	log      *log.Helper
	ucButton *biz.ButtonUsecase
}

func NewButtonService(uc *biz.ButtonUsecase, logHelpers *settings.LogHelpers) *ButtonService {
	return &ButtonService{ucButton: uc, log: logHelpers.Server}
}

func (s *ButtonService) CreateButton(
	ctx context.Context,
	req *pb.CreateButtonRequest,
) (*pb.ButtonReply, error) {
	im := biz.ButtonModel{
		Name:         req.Name,
		ArrangeOrder: req.ArrangeOrder,
		IsActive:     req.IsActive,
		Descr:        req.Descr,
	}
	om, err := s.ucButton.CreateButton(ctx, req.MenuId, req.PermissionIds, im)
	if err != nil {
		return nil, err
	}
	data, err := ButtonSchemasOut(ctx, s.log, *om)
	return &pb.ButtonReply{Code: http.StatusCreated, Message: "", Metadata: data}, err
}

func (s *ButtonService) UpdateButton(
	ctx context.Context,
	req *pb.UpdateButtonRequest,
) (*pb.ButtonReply, error) {
	im := biz.ButtonModel{
		Id:           req.Pk,
		Name:         req.Name,
		ArrangeOrder: req.ArrangeOrder,
		IsActive:     req.IsActive,
		Descr:        req.Descr,
	}
	om, err := s.ucButton.UpdateButtonById(ctx, req.Pk, req.MenuId, req.PermissionIds, im)
	if err != nil {
		return nil, err
	}
	data, err := ButtonSchemasOut(ctx, s.log, *om)
	return &pb.ButtonReply{Code: http.StatusOK, Message: "", Metadata: data}, err
}

func (s *ButtonService) DeleteButton(
	ctx context.Context,
	req *pb.DeleteButtonRequest,
) (*pb.ButtonReply, error) {
	err := s.ucButton.DeleteButtonById(ctx, req.Pk)
	return &pb.ButtonReply{Code: http.StatusOK, Message: "", Metadata: nil}, err
}

func (s *ButtonService) GetButton(
	ctx context.Context,
	req *pb.GetButtonRequest,
) (*pb.ButtonReply, error) {
	om, err := s.ucButton.FindButtonByID(ctx, []string{"Menu", "Permissions"}, req.Pk)
	if err != nil {
		return nil, err
	}
	data, err := ButtonSchemasOut(ctx, s.log, *om)
	return &pb.ButtonReply{Code: http.StatusOK, Message: "", Metadata: data}, err
}

func (s *ButtonService) ListButton(
	ctx context.Context,
	req *pb.ListButtonRequest,
) (*pb.PagButtonReply, error) {
	page, size, query := s.filterButton(req)
	count, ms, err := s.ucButton.ListButton(ctx, nil, page, size, query)
	if err != nil {
		return nil, err
	}
	mso, err := ListButtonModelToSchemasOutBase(ctx, s.log, ms)
	if err != nil {
		return nil, err
	}
	rsp := pb.PagButtonOutBase{
		Items: mso,
		Page:  int64(page),
		Pages: core.CountPages(count, int64(size)),
		Size:  int64(size),
		Total: count,
	}
	return &pb.PagButtonReply{Code: http.StatusOK, Message: "", Metadata: &rsp}, nil
}

func (uc *ButtonService) filterButton(
	req *pb.ListButtonRequest,
) (int, int, map[string]any) {
	var (
		page  int            = core.DefaultPage
		size  int            = core.DefaultSize
		query map[string]any = make(map[string]any)
	)
	if req != nil {
		if req.Page > 0 {
			page = int(req.Page)
		}
		if req.Size > 0 {
			size = int(req.Size)
		}
		if req.Pk != 0 {
			query["id = ?"] = req.Pk
		} else if req.Pks != "" {
			pks := core.StringToListUint32(req.Pks)
			if len(pks) > 1 {
				query["id in ?"] = pks
			}
		}
		if req.Name != "" {
			query["name like ?"] = req.Name
		}
		if req.IsActive != nil {
			query["is_active = ?"] = req.IsActive
		}
		if req.MenuId != 0 {
			query["menu_id = ?"] = req.MenuId
		}
	}
	return page, size, query
}
